
#include <rtthread.h>

#include "rt_lv_port_disp.h"

static rt_device_t _lcd_device = RT_NULL;
struct rt_device_graphic_info _lcd_info;
struct rt_device_graphic_ops *_lcd_ops = RT_NULL;
/**********************
 *   STATIC FUNCTIONS
 **********************/
/* Flush the content of the internal buffer the specific area on the display
 * You can use DMA or any hardware acceleration to do this operation in the background but
 * 'lv_disp_flush_ready()' has to be called when finished. */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

    int32_t x;
    int32_t y;
    for (y = area->y1; y <= area->y2; y++)
    {
        if (_lcd_ops && _lcd_ops->blit_line)
        {
            _lcd_ops->blit_line((const char *)color_p, area->x1, y, (area->x2 - area->x1));

            color_p += (area->x2 - area->x1 + 1);
        }
        else
        {
            for (x = area->x1; x <= area->x2; x++)
            {
                /* Put a pixel to the display. For example: */
                if (_lcd_ops && _lcd_ops->set_pixel)
                    _lcd_ops->set_pixel((const char*) color_p, x, y);
                color_p++;
            }
        }
    }

    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}


/**********************
 *   GLOBAL FUNCTIONS
 **********************/
void lv_port_disp_init(void)
{
    /*-------------------------
     * Initialize your display
     * -----------------------*/
    _lcd_device = rt_device_find("lcd");
    RT_ASSERT(_lcd_device != RT_NULL);
    if (rt_device_open(_lcd_device, RT_DEVICE_OFLAG_RDWR) == RT_EOK)
    {
        rt_device_control(_lcd_device, RTGRAPHIC_CTRL_GET_INFO, &_lcd_info);

        _lcd_ops = (struct rt_device_graphic_ops *)_lcd_device->user_data;
    }

    static lv_disp_buf_t disp_buf;
    /* Example for 2) */
    static lv_color_t buf_1[LV_HOR_RES_MAX * 10]; /*A buffer for 10 rows*/
    static lv_color_t buf_2[LV_HOR_RES_MAX * 10]; /*A buffer for 10 rows*/
    lv_disp_buf_init(&disp_buf, buf_1, buf_2, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/

    /*-----------------------------------
     * Register the display in LittlevGL
     *----------------------------------*/

    lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv); /*Basic initialization*/

    /*Set up the functions to access to your display*/

    /*Set the resolution of the display*/
    disp_drv.hor_res = _lcd_info.width;
    disp_drv.ver_res = _lcd_info.height;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;

    /*Set a display buffer*/
    disp_drv.buffer = &disp_buf;

#if LV_USE_GPU
    /*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/

    /*Blend two color array using opacity*/
    disp_drv.gpu_blend_cb = gpu_blend;

    /*Fill a memory array with a color*/
    disp_drv.gpu_fill_cb = gpu_fill;
#endif

    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
    lv_disp_flush_ready(&disp_drv);
}

